﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Metadata;
using System.ServiceModel;
using System.Xml;
using System.IO;

namespace counter
{
    public class counter : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
              serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));

            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

                if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
                {
                    Entity entity = (Entity)context.InputParameters["Target"];
                    string nextAutoNumber = "";

                    XmlDataDocument xmldoc = new XmlDataDocument();
                    XmlNodeList xmlnode;
                    Boolean nextNumberGenerated = false;
                    int lineno = 0; string nextNumberInfo = ""; string targetField = ""; int incrNumber = 0; string counterRecordID = "";
                    int nextnumber = 0;
                    try
                    {
                        lineno = 1;
                        string myxml = GenerateXMLforEntityConfig(entity.LogicalName, service);
                        if (myxml == "") throw new Exception("Invalid XML Defined !!");
                        xmldoc.LoadXml(myxml);

                        lineno = 2;
                        xmlnode = xmldoc.GetElementsByTagName("Field");
                        XmlNodeList allsessions = xmldoc.SelectNodes("Fields/Field");
                        lineno = 3;
                        foreach (XmlNode eachsession in allsessions)
                        {
                            XmlNodeList mainnode = eachsession.SelectNodes("fieldname");
                            
                            string fieldname =  mainnode.Item(0).InnerText.ToString();
                            lineno = 4;
                            
                            XmlNodeList allParam = eachsession.SelectNodes("parameter");
                            lineno = 5;
                            foreach (XmlNode eachParam in allParam)
                            {
                        
                                XmlNodeList vnode = eachParam.SelectNodes("value");
                                string fieldvalue = vnode.Item(0).InnerText.ToString();
                                lineno = 6;
                                
                                XmlNodeList vparam1 = eachParam.SelectNodes("prefix");
                                string fieldprefix =  vparam1.Item(0).InnerText.ToString();
                                lineno = 7;

                                XmlNodeList vparam2 = eachParam.SelectNodes("suffix");
                                string fieldsuffix = vparam2.Item(0).InnerText.ToString();
                                lineno = 7;
                                
                                nextNumberInfo = GenerateCounterNumber(entity.LogicalName, service);

                                lineno = 8;
                                string[] nextNumberInfoItems = nextNumberInfo.Split('$');
                                lineno = 9;
                                int lengthofnextnumber = nextNumberInfoItems[0].ToString().Length;
                                int.TryParse(nextNumberInfoItems[0].ToString(), out nextnumber);
                                lineno = 10;
                                targetField = nextNumberInfoItems[1];
                                lineno = 11;
                                int maxlength; int.TryParse(nextNumberInfoItems[2].ToString(), out maxlength);
                                int.TryParse(nextNumberInfoItems[3].ToString(),out incrNumber);
                                counterRecordID = nextNumberInfoItems[4].ToString();

                                lineno = 111;

                                if (entity.Attributes.Contains(fieldname) == true)
                                {
                                    lineno = 12;
                                    if (entity.Attributes[fieldname].GetType().FullName == "Microsoft.Xrm.Sdk.OptionSetValue")
                                    {
                                        if (((Microsoft.Xrm.Sdk.OptionSetValue)((entity.Attributes[fieldname]))).Value.ToString() == fieldvalue)
                                        {
                                            lineno = 13;
                                            nextAutoNumber = nextAutoNumber + fieldprefix;
                                            for (int i = lengthofnextnumber; i < maxlength; i++) nextAutoNumber = nextAutoNumber + "0";
                                            lineno = 14;
                                            nextAutoNumber = nextAutoNumber + nextnumber;
                                            if (fieldprefix != "") nextAutoNumber = nextAutoNumber + fieldsuffix;
                                            nextNumberGenerated = true;
                                            lineno = 15;
                                        }
                                    }
                                    else
                                    {
                                        if (entity.Attributes[fieldname].ToString() == fieldvalue)
                                        {
                                            lineno = 13;
                                            nextAutoNumber = nextAutoNumber + fieldprefix;
                                            for (int i = lengthofnextnumber; i < maxlength; i++)
                                            {
                                                nextAutoNumber = nextAutoNumber + "0";
                                            }
                                            lineno = 14;
                                            nextAutoNumber = nextAutoNumber + nextnumber;
                                            if (fieldprefix != "") nextAutoNumber = nextAutoNumber + fieldsuffix;
                                            nextNumberGenerated = true;
                                            lineno = 15;
                                        }

                                    }
                                }
                            }

                         }
                        lineno = 16;
                        if (nextNumberGenerated == true)
                        {
                            lineno = 17;
                            entity.Attributes[targetField] = nextAutoNumber;
                            lineno = 18;
                            service.Update(entity);
                            string increply = IncrementNextNumber(entity.LogicalName,nextnumber, counterRecordID, service);
                            if (increply != "success") throw new Exception("Auto Number not updated in counter config !!");

                        }
                        lineno = 19;
                    }
                    catch (FaultException<OrganizationServiceFault> ex)
                    {
                        throw new InvalidPluginExecutionException("An error occurred in the counter plug-in.", ex);
                    }
                
                    catch (Exception ex)
                    {
                        throw new Exception("Other Error !! " + ex.Message.ToString() + " at line " + lineno.ToString() + "//" + nextNumberInfo.ToString());
                    }
                }

            }


        public string  IncrementNextNumber(string entityname, int nextNo , string cntRecordID, IOrganizationService service)
        {
            try
            {
                Entity entcounter = new Entity("new_autonumber");
                ColumnSet attributes = new ColumnSet(new string[] { "new_nextnumber"});

                entcounter = service.Retrieve("new_autonumber",new Guid(cntRecordID),attributes);
                entcounter["new_nextnumber"] = nextNo;
                service.Update(entcounter);
                return "success";
                
            }
            catch (Exception ex)
            {
                return "Error" + ex.Message.ToString();
            }
        }


        public string GenerateCounterNumber(string entityname , IOrganizationService service)
        {
            try
            {
                var fetchXml = @"<fetch mapping='logical' version='1.0'>
                <entity name='new_autonumber'><all-attributes/>  <filter type='and'>" +
                                    "<condition attribute='new_name' operator='eq' value='" + entityname.ToString() + "' /> </filter> </entity> </fetch>";

                // Run the query with the FetchXML.

                var fetchExpression = new FetchExpression(fetchXml);
                EntityCollection fetchResult = service.RetrieveMultiple(fetchExpression);

                if (fetchResult.Entities.Count > 0)
                {
                    
                    int incrNumber = (int)fetchResult.Entities[0].Attributes["new_incrementby"];
                    decimal nextnumber = (decimal)fetchResult.Entities[0].Attributes["new_nextnumber"];
                    string targetField = fetchResult.Entities[0].Attributes["new_targetfield"].ToString();
                    int maxlength = (int)fetchResult.Entities[0].Attributes["new_maxlength"];
                    Guid counterRecordID = new Guid(fetchResult.Entities[0].Attributes["new_autonumberid"].ToString());

                    int newnumber = (int)nextnumber + incrNumber;

                    return newnumber.ToString() + "$" + targetField.ToString() + "$" + maxlength.ToString() + "$" + incrNumber.ToString() + "$" + counterRecordID.ToString();
              
                }
                else { return "notfound"; }
            }
            catch (Exception ex)
            {
                return "Error" + ex.Message.ToString();
            }
       }


        public string GenerateXMLforEntityConfig(string entityname, IOrganizationService service)
        {
            try
            {
                var fetchXml = @"<fetch mapping='logical' version='1.0'>
                <entity name='new_autonumber'><all-attributes/>  <filter type='and'>" +
                                    "<condition attribute='new_name' operator='eq' value='" + entityname.ToString() + "' /> </filter> </entity> </fetch>";

                // Run the query with the FetchXML.

                var fetchExpression = new FetchExpression(fetchXml);
                EntityCollection fetchResult = service.RetrieveMultiple(fetchExpression);

                if (fetchResult.Entities.Count > 0)
                {
                    return fetchResult.Entities[0].Attributes["new_fieldmapping"].ToString();
                }
                else { return "notfound"; }
            }
            catch (Exception ex)
            {
                return "Error" + ex.Message.ToString();
            }
        }


    }
}
